#include "pch.h"
#include "list.h"
#include "Label.h"
#include "Image.h"
#include "CheckBox.h"

namespace mini
{
	namespace ui
	{
		static float itemHeight = 20.0f;
		CList::CList()
		{
			mWndType = ui_list;
			mState = Status_Normal;
			auto defaultUpdate = [](mini::ui::CList*, mini::ui::CList::listItem*) {};
			auto defaultClick = [](bool, mini::ui::CList::listItem*) {};
			mfuncMouseWheel = [](int) {};
			mfuncMouseMove = [](int,int) {};
			mfuncSelect = defaultClick;
			mfuncDoubleSelect = defaultClick;
			mfuncUpdate = defaultUpdate;
		}

		CList::CList(const std::string text) : CList()
		{
			setWndName(text);
		}

		CList::~CList()
		{
			SafeDelete(mpChooseItem);
			SafeDelete(mpBGWnd);
		}

		CList::listItem*  CList::createItem(const std::string& name)
		{
			switch (mMode)
			{
			case CList::tree:
				return _createItemTree(name);
			case CList::list:
				return _createItemList(name);
			case CList::box:
				return _createItemBox(name);
			}
			return nullptr;
		}
		
		void CList::addItem(CList::listItem* pItem, const std::string& name)
		{
			if (nullptr != pItem)
			{
				auto pChildItem = createItem(name);
				pChildItem->mParentListItem = pItem;
				pItem->mpChildItem.push_back(pChildItem);
				pItem->mpWnd->addChildWnd(pChildItem->mpWnd);
				pChildItem->mpWnd->Release();
				_updateItemPlace(mListItem.mpChildItem, 0, 0);

			}
		}

		CList::listItem* CList::findRootItem(const std::string& name)
		{
			for (auto pItem : mListItem.mpChildItem)
			{
				if (nullptr != pItem->mpWnd &&
					pItem->mpWnd->getWndName() == name)
				{
					return pItem;
				}
			}
			return nullptr;
		}

		std::pair<CList::listItem*,int> CList::findChildItem(CList::listItem* pItem, const std::string& name, int nBegin)
		{
			std::pair<CList::listItem*, int> result;
			result.first = nullptr;
			result.second = -1;

			if (nullptr != pItem)
			{
				int nLocalBegin = 0;
				auto nb = pItem->mpChildItem.begin();
				auto ne = pItem->mpChildItem.end();
				for (; nb != ne; ++nb)
				{
					if (nLocalBegin++ > nBegin)
					{
						if ((*nb)->mpWnd->getWndName() == name)
						{
							result.first = (*nb);
							result.second = nLocalBegin;
							break;
						}
					}
				}
			}

			return result;
		}

		CList::listItem* CList::addRootItem(const std::string& name)
		{
			auto pItem = createItem(name);
			if (nullptr != pItem)
			{
				addChildWnd(pItem->mpWnd);
				mListItem.mpChildItem.push_back(pItem);
				pItem->mParentListItem = nullptr;
				pItem->mpWnd->Release();
				_updateItemPlace(mListItem.mpChildItem, 0, 0);
			}
			return pItem;
		}

		void CList::deleteItem(CWnd* pItem)
		{
			if (nullptr != pItem)
			{
				auto nBegin = mListItem.mpChildItem.begin();
				auto nEnd = mListItem.mpChildItem.end();
				for (; nBegin != nEnd; ++nBegin)
				{
					if ((*nBegin)->mpWnd == pItem)
					{
						SafeRelease((*nBegin)->mpWnd);
						SafeDelete((*nBegin));
						mListItem.mpChildItem.erase(nBegin);
						break;
					}
				}
			}
		}

		void CList::deleteItem(int nPosition)
		{
			if (nPosition < static_cast<int>(mListItem.mpChildItem.size()) &&
				nPosition > -1)
			{
				auto nBegin = mListItem.mpChildItem.begin();
				auto nEnd = mListItem.mpChildItem.end();
				int nIndex = 0;
				for (; nBegin != nEnd; ++nBegin, ++nIndex)
				{
					if (nIndex == nPosition)
					{
						SafeRelease((*nBegin)->mpWnd);
						SafeDelete((*nBegin));
						mListItem.mpChildItem.erase(nBegin);
						break;
					}
				}
			}
		}

		void CList::deleteItem(int nPosition, int nBegin)
		{
			if (nPosition < (int)mListItem.mpChildItem.size())
			{
				auto nB = mListItem.mpChildItem.begin();
				auto nE = mListItem.mpChildItem.end();
				int i = 0;
				for (; nB != nE; ++nB)
				{
					if (i++ == nPosition)
					{
						if (nBegin == -1)
						{

						}
						else
						{

						}
						break;
					}
				}
			}
		}

		void CList::deleteAllItem()
		{
			for (auto pItem : mListItem.mpChildItem)
			{
				SafeRelease(pItem->mpWnd);	
				SafeDelete(pItem);	
			}
			mListItem.mpChildItem.clear();
			mpChooseItem = nullptr;
		}

		void CList::deleteAllItem(CList::listItem* pItems)
		{
			if (pItems->mpChildItem.size())
			{
				for (auto pItem : pItems->mpChildItem)
				{
					SafeRelease(pItem->mpWnd);
					SafeDelete(pItem);
				}
				pItems->mpChildItem.clear();
				_updateItemPlace(mListItem.mpChildItem, 0, 0);
			}
		}

		void CList::selectItem(CList::listItem* pItem)
		{
			mfuncSelect(false, pItem);
			mfuncUpdate(this, pItem);
		}

		void CList::doubleClickItem(CList::listItem* pItem)
		{
			mfuncDoubleSelect(true, pItem);
		}

		void CList::mouseWheel(int iMessage)
		{
			mfuncMouseWheel(iMessage);
		}

		void CList::mouseMove(int x, int y)
		{
			mfuncMouseMove(x, y);
		}

		void CList::setSelectContentFunc(std::function<void(CList* pList, CList::listItem*)> func)
		{
			mfuncUpdate = func;
		}

		void CList::setSelectItemFunc(std::function<void(bool, CList::listItem*)> func)
		{
			mfuncSelect = func;
		}

		void CList::setDoubleClickItemFunc(std::function<void(bool, CList::listItem*)> func)
		{
			mfuncDoubleSelect = func;
		}

		void CList::setMouseWheelFunc(std::function<void(int)> func)
		{
			mfuncMouseWheel = func;
		}

		void CList::setMouseMoveFunc(std::function<void(int, int)> func)
		{
			mfuncMouseMove = func;
		}

		CList::listItem* CList::getChooseItem()
		{
			return mpChooseItem;
		}

		void CList::setMode(ControlMode mode)
		{
			mMode = mode;
			for (auto pItem : mListItem.mpChildItem)
			{
				removeChildWnd(pItem->mpWnd);
				SafeRelease(pItem->mpWnd);
				SafeDelete(pItem);
			}
			mListItem.mpChildItem.clear();
		}

		CList::ControlMode CList::getMode()
		{
			return mMode;
		}

		CList::listItem* CList::_createItemTree(const std::string& name)
		{
			auto pWnd = new CWnd();
			pWnd->disable();
			listItem* pItem = new listItem;
			pItem->mpWnd = pWnd;
			pWnd->setPosition(0, 0);

			pWnd->setSize(getSize().x, itemHeight);
			pWnd->setGuiStyle("Blue");
			pWnd->setDrawSelf(false);
			auto size = pWnd->getSize();

			CCheckBox* pCheckBox = new CCheckBox();
			pWnd->addChildWnd(pCheckBox);
			pCheckBox->positionOffset(0, 0);
			pCheckBox->setSize(itemHeight, itemHeight);
			pCheckBox->setGuiStyle("listCheckBox");

			CLabel* pLable = new CLabel();
			pLable->disable();
			pWnd->addChildWnd(pLable);
			pLable->positionOffset(30, 0);
			pLable->setSize(size.x, itemHeight);
			pLable->setGuiStyle("default");
			pLable->setWindowText(name);
			
			pItem->mText = name;
			
			GuiStyle* pGuiStyle = gGuiStyleManager->loadGuiStyle("default", ui_font);

			if (nullptr != pGuiStyle)
			{
				FontStyle* pFontStyle = dynamic_cast<FontStyle*>(pGuiStyle);
				pLable->setFont(pFontStyle->mpFont, CPoint4F(0,0,0,1), CPoint2F(18,18), ShowMode::Left | ShowMode::U_Center);
			}
			SafeRelease(pCheckBox);
			SafeRelease(pLable);
			return pItem;
		}

		CList::listItem*  CList::_createItemList(const std::string& name)
		{
			auto pWnd = new CWnd();
			pWnd->disable();
			listItem* pItem = new listItem;
			pItem->mpWnd = pWnd;
			pWnd->setPosition(0, 0);

			pWnd->setSize(getSize().x, itemHeight);
			pWnd->setGuiStyle("Blue");
			pWnd->setDrawSelf(false);
			auto size = pWnd->getSize();

			CImage* pImage = new CImage();
			pImage->disable();
			pWnd->addChildWnd(pImage);
			
			pImage->positionOffset(0, 0);
			pImage->setSize(20, 20);
			pImage->setGuiStyle("actorIcon");

			CLabel* pLable = new CLabel();
			pLable->disable();
			pWnd->addChildWnd(pLable);
			pLable->positionOffset(21, 0);
			pLable->setSize(size.x, itemHeight);
			pLable->setGuiStyle("default");
		
			GuiStyle* pGuiStyle = gGuiStyleManager->loadGuiStyle("default", ui_font);
			if (nullptr != pGuiStyle)
			{
				FontStyle* pFontStyle = dynamic_cast<FontStyle*>(pGuiStyle);
				pLable->setFont(pFontStyle->mpFont, CPoint4F(0, 0, 0, 1), CPoint2F(14, 14), ShowMode::Left | ShowMode::U_Center);
			}
			pLable->setWindowText(name);
			pItem->mText = name;

			SafeRelease(pImage);
			SafeRelease(pLable);
			return pItem;
		}

		CList::listItem*  CList::_createItemBox(const std::string& name)
		{
			auto pWnd = new CWnd();

			listItem* pItem = new listItem;
			pItem->mpWnd = pWnd;
			pWnd->setPosition(0, 0);
			pWnd->setSize(mBoxItemSize, mBoxItemSize + 20);
			pWnd->setGuiStyle("Blue");
			pWnd->setDrawSelf(false);
			auto size = pWnd->getSize();

			CImage* pImage = new CImage();
			pImage->disable();
			pWnd->addChildWnd(pImage);
			pImage->positionOffset(0, 0);
			pImage->setSize(mBoxItemSize, mBoxItemSize);
			pImage->setGuiStyle("actorIcon");

			CLabel* pLable = new CLabel();
			pLable->disable();
			pWnd->addChildWnd(pLable);
			pLable->positionOffset(0, mBoxItemSize + 1);
			pLable->setSize(mBoxItemSize, 20);
			pLable->setGuiStyle("default");
			GuiStyle* pGuiStyle = gGuiStyleManager->loadGuiStyle("default", ui_font);
			if (nullptr != pGuiStyle)
			{
				FontStyle* pFontStyle = dynamic_cast<FontStyle*>(pGuiStyle);
				pLable->setFont("default", CPoint4F(0, 0, 0, 1), CPoint2F(14, 14), ShowMode::Center);
			}

			pLable->setWindowText(name);
			pItem->mText = name;

			SafeRelease(pImage);
			SafeRelease(pLable);

			return pItem;
		}

		CList::listItem* CList::_checkListItem(CList::listItem * pItemList, event& e)
		{
			CList::listItem* pItem = nullptr;
			for (auto item : pItemList->mpChildItem)
			{
				pItem = _checkListItem(item, e);
				if (nullptr != pItem)
				{
					return pItem;
				}
			}
			if (IsSpace(e.point, pItemList->mpWnd))
			{
				return pItemList;
			}
			else
			{
				return nullptr;
			}
		}

		int CList::_updateItemPlace(std::list<CList::listItem*>& pItems, int xOffset, int yOffset)
		{
			if (mMode != box)   
			{
				for (auto pItem : pItems)
				{
					if (nullptr != pItem->mpWnd)
					{
						pItem->mpWnd->setPosition((float)xOffset, (float)yOffset);
					}
					if (pItem->mbDrop && pItem->mpChildItem.size() > 0)
					{
						int yChildOffset = 20;
						yOffset += _updateItemPlace(pItem->mpChildItem, xOffset + 10, yChildOffset);
					}
					else
					{
						yOffset += 20;
					}
				}
				return yOffset;
			}
			else
			{
				int i = 0;
				int nCount = static_cast<int>(pItems.size());
				int nLineNumber = static_cast<int>(mSize.x / mBoxItemSize);
				for (auto pItem : pItems)
				{
					if (i >= nLineNumber)
					{
						int x = i / nLineNumber;
						int y = i % nLineNumber;
						pItem->mpWnd->setPosition((float)y * (mBoxItemSize), (float)x * (mBoxItemSize + 20));
					}
					else
					{
						pItem->mpWnd->setPosition((float)i * (mBoxItemSize), 0);
					}
					++i;
				}
				return 0;
			}
		}
	}
}
